package com.reger.core.code;

import java.util.concurrent.atomic.AtomicInteger;
import java.util.concurrent.atomic.AtomicLong;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
 * 
 * 根据36进制生产序列字符串（36进制包括大写小写字母和数字，区分大小写）
 * 该序列合理使用理论上可以永远不重复
 * @author leige
 *
 */
public final class Sequence36 {

	private static final Logger LOGGER = LoggerFactory.getLogger(Sequence36.class);
	private static final short LENGTH=TransforCode36String.getLength();;
	private volatile static String empty = new String(TransforCode36String.serialize(0L));
	private volatile static short cycle = 0;
	private volatile static String cycleStr = empty;
	private volatile static AtomicInteger serverid  = new AtomicInteger(0);
	private volatile static String serveridStr = empty + empty;
    private volatile static AtomicLong sequence = new AtomicLong(0);  
	private volatile static AtomicLong endTime =new AtomicLong(1 +  (System.currentTimeMillis() / 60000/60))  ; // 记录周期结束时间戳，以小时为单位
	
	/**
	 * 原子性修改周期结束时间
	 * @param curTime
	 * @return 是否修改成功
	 */
	private final static boolean compareAndSet(long curTime) {
		long runTime=curTime/60; // 的到以小时为单位的时间
		endTime.updateAndGet(operand->operand<runTime?runTime:operand);
		return endTime.compareAndSet(runTime, runTime+1);
	}
 
	/**
	 * 产生一个序列串,如 01-0073zg1-0-000001, 01 服务器标识，0073zg1 以分钟为单位的时间戳标识， 0 周期标识， 000001 序列标识 ,小写字母和数字
	 * @return
	 */
	public final static String generate() {
		if(serverid.compareAndSet(0, 1)){
			short serverid=(short)(Math.random()*LENGTH*LENGTH);
			setServerid(serverid);
			LOGGER.warn("请注意,Sequence序列未设置服务器id,多台服务器有可能会生成相同的序列,随机产生的服务器id {}",serverid);
		}
		long runTime =(int)( System.currentTimeMillis() / 60000); //当前以分钟为单位的时间戳
		String dserveridStr =serveridStr;
		long dSequence36;
		String dcycleStr;
		if (compareAndSet(runTime)) {//进入下一个周期
			cycle = (short) (++cycle % LENGTH); //周期号
			sequence.set(0);
			cycleStr = new String(TransforCode36String.serialize((long) cycle));
			dSequence36=0; //周期开始序列重新开始
			dcycleStr=cycleStr; // 计算周期号标识
		}else{
			dcycleStr=cycleStr;
			dSequence36 = sequence.incrementAndGet(); //序列自增
		}
		StringBuffer buffer = new StringBuffer();
		addFormat(buffer, TransforCode36String.serialize(runTime), 7); // 7位,可以持续使用超过万年
		buffer.append('-');
		buffer.append(dserveridStr); // 2位,可以容纳 3844台服务器
		buffer.append('-');
		buffer.append(dcycleStr); // 1位，周期标识，周期为36
		buffer.append('-');
		addFormat(buffer, TransforCode36String.serialize( dSequence36), 6); // 6位，支持每小时生产36的的6次幂个不同的序列
		return buffer.toString();
	}
 
	private static void addFormat(StringBuffer buffer, String str, int length) {
		int addNum = length - str.length();
		if (addNum > 0)
			for (int i = 0; i < addNum; i++) {
				buffer.append(empty);
			}
		buffer.append(str);
	}
	
	/**
	 * 获取服务器标识
	 * @return
	 */
	public static short getServerid() {
		long serverid = TransforCode36String.deserialize(serveridStr);
		return (short) serverid;
	}
 
	/**
	 * 设置服务器编号，必须大于0
	 * @param serverid
	 */
	public synchronized static void setServerid(short serverid) {
		Sequence36.serverid.set(serverid);
		Sequence36.serveridStr = new String(TransforCode36String.serialize((long) serverid));
		if (Sequence36.serveridStr.length() == 1)
			Sequence36.serveridStr = empty + Sequence36.serveridStr;
	}
 
}
